﻿using MongoDB.Driver;
using Sustainalytics.Entities;
using Sustainalytics.Synchronization.Validation.Entities.CorporateGovernance;
using Sustainalytics.Synchronization.Validation.Handlers.Common;
using Sustainalytics.Synchronization.Validation.Validators;
using System;
using System.Threading.Tasks;

namespace Sustainalytics.Synchronization.Validation.Handlers.CorporateGovernance
{
    public class GovernanceProfileHandler : IHandler
    {
        private readonly CorporateGovernanceCompanies companies;
        private readonly HandlerWithGrouping<GovernanceIndicator> indicatorHandler;

        private readonly HandlerWithGrouping<GovernanceIssue> issuesHandler;

        private readonly IMongoCollection<GovernanceCompanyProfile> profileMongoCollection;
        private readonly Validator<GovernanceValidationProfile> validator;

        public GovernanceProfileHandler(
            IMongoCollection<GovernanceCompanyProfile> profileMongoCollection,
            HandlerWithGrouping<GovernanceIndicator> indicatorHandler,
            HandlerWithGrouping<GovernanceIssue> issuesHandler,
            Validator<GovernanceValidationProfile> validator,
            CorporateGovernanceCompanies companies)
        {
            this.profileMongoCollection = profileMongoCollection;
            this.indicatorHandler = indicatorHandler;
            this.issuesHandler = issuesHandler;
            this.validator = validator;
            this.companies = companies;
        }

        public virtual async Task ForEachElementsAsync(Action<ValidationResult> validationCallback)
        {
            if (validator.HasAssignedRules)
            {
                await profileMongoCollection.Find(Builders<GovernanceCompanyProfile>.Filter.Empty)
                    .Project<GovernanceCompanyProfile>(Builders<GovernanceCompanyProfile>.Projection
                    .Include(x => x.Id)
                    .Include(x => x.FullProfile)
                    .Include(x => x.AnalystView)
                    .Include(x => x.Outlook))
                    .ForEachAsync(async profile =>
                    {
                        if (!companies.Contains(profile.Id))
                        {
                            return;
                        }

                        var currentGovernanceProfile = new GovernanceValidationProfile
                        {
                            CompanyId = profile.Id,
                            FullProfile = profile.FullProfile,
                            AnalystView = profile.AnalystView,
                            Outlook = profile.Outlook,
                            GovernanceIssues = await issuesHandler.GetValidatedElementAsync(profile.Id).ConfigureAwait(false),
                            GovernanceIndicators = await indicatorHandler.GetValidatedElementAsync(profile.Id).ConfigureAwait(false)
                        };

                        var previousGovernanceProfile = new GovernanceValidationProfile
                        {
                            CompanyId = profile.Id,
                            FullProfile = profile.FullProfile,
                            AnalystView = profile.AnalystView,
                            Outlook = profile.Outlook,
                            GovernanceIssues = await issuesHandler.GetReferenceElementsAsync(profile.Id).ConfigureAwait(false),
                            GovernanceIndicators = await indicatorHandler.GetReferenceElementsAsync(profile.Id).ConfigureAwait(false)
                        };

                        var validationResult = await validator.ValidateAsync(currentGovernanceProfile, previousGovernanceProfile).ConfigureAwait(false);

                        validationCallback.Invoke(validationResult);
                    }).ConfigureAwait(false);
            }
        }
    }
}
